#pragma once


#include <cstddef>
#include <algorithm>
#include <utility>
#include <type_traits>
#include <functional>
#include <limits>
#include <assert.h>


#include "../utility.hpp"
#include "../type_traits.hpp"
#include "../config/config_begin.h"

namespace cpp
{
	static constexpr const size_t variant_npos = (size_t)-1;
	template <class... Types>
	class variant;

	namespace __variant
	{
		inline namespace helper
		{
			template<class Alloc, class...Args>
			auto _Forward(Alloc&& a, std::true_type, std::true_type, Args&& ...args)
			{
				return std::forward_as_tuple(std::forward<Args>(args)..., std::forward<Alloc>(a));
			}

			template<class Alloc, class...Args>
			auto _Forward(Alloc&& a, std::true_type, std::false_type, Args&& ...args)
			{
				return std::forward_as_tuple(std::allocator_arg, std::forward<Alloc>(a), std::forward<Args>(args)...);
			}

			template<class Alloc, class NotCare, class...Args >
			auto _Forward(Alloc&&, std::false_type, NotCare&&, Args&& ...args)
			{
				return std::forward_as_tuple(std::forward<Args>(args)...);
			}

			template<class T, class Alloc, class...Args>
			auto _ForwardAllocConstructorArgs(Alloc&& a, Args&& ... args)
			{
				return	helper::_Forward(std::forward<Alloc>(a), std::uses_allocator<T, Alloc>{	}, std::is_constructible<T, Args..., Alloc >{}, std::forward<Args>(args)...);
			}


			struct _DummyEmpty {};

			struct _AnyType { template<class T> operator T && (); };

			template<std::size_t size, class ...Types>
			struct _Overload;

			template<std::size_t size, class T, class ...Types>
			struct _Overload<size, T, Types...> : _Overload< size, Types...>
			{
				static const std::size_t _R = _Overload<size, Types...>::_R + 1;
				static const std::size_t index = size - _R;
				static std::integral_constant<std::size_t, index> select(T, std::integral_constant<std::size_t, index>);

				using  _Overload< size, Types...>::select;
			};

			template<std::size_t size, class T>
			struct _Overload<size, T>
			{
				static const std::size_t _R = 1;
				static const std::size_t index = size - _R;
				static std::integral_constant<std::size_t, index> select(T, std::integral_constant<std::size_t, index>);
			};

			template<class T, class...Args>
			struct _OverloadTest : _Overload<sizeof...(Args), Args...>
			{
				using  _Overload<sizeof...(Args), Args...>::select;
				static std::integral_constant<std::size_t, std::size_t(-1) > select(...);

				static const std::size_t value = decltype(select(std::declval<T>(), std::declval<_AnyType>()))::value;
			};

			template<class T, class...Args>
			struct _OverloadIndexOf :
				std::conditional_t<  _OverloadTest<T, Args...>::value == std::size_t(-1), _DummyEmpty, std::integral_constant<std::size_t, _OverloadTest<T, Args...>::value >  >
			{

			};

			//////////////////////////////////////////////////////////////////////////
			template< class T, std::size_t, class ...Types>
			struct _IndexOfHelper;

			template<class T, std::size_t index, class Ti, class ...Types>
			struct _IndexOfHelper<T, index, Ti, Types...> : _IndexOfHelper<T, index + 1, Types...>
			{
				static const std::size_t value = _IndexOfHelper<T, index + 1, Types...>::value;

				static const std::size_t count = _IndexOfHelper<T, index + 1, Types...>::count;
			};

			template<class T, std::size_t index, class ...Types>
			struct _IndexOfHelper<T, index, T, Types...> :_IndexOfHelper<T, index + 1, Types...>
			{
				static const std::size_t value = index;
				static const std::size_t count = _IndexOfHelper<T, index + 1, Types...>::count + 1;
			};

			template<class T, std::size_t index>
			struct _IndexOfHelper<T, index>
			{
				static const std::size_t value = index;
				static const std::size_t count = 0;
			};


			template<class T, class...Types>
			struct _IndexOf
				: std::conditional_t <
				_IndexOfHelper<T, 0, Types...>::count == 1,
				std::integral_constant<std::size_t, _IndexOfHelper<T, 0, Types...>::value>,
				_DummyEmpty  >
			{

			};


			template<class T>
			T _Declval() noexcept;// should not use std::declval<T>()

			////
			template<class... _Ty>
			struct _CommonType;

			template<class _Ty>
			struct _CommonType<_Ty>
			{
				typedef _Ty type;
			};

			template<class _Ty0, class _Ty1>
			struct _CommonType<_Ty0, _Ty1>
			{
				typedef decltype(false ? _Declval<_Ty0>() : _Declval<_Ty1>()) type;
			};

			template<class _Ty0, class _Ty1,
				class... _Ty>
				struct _CommonType<_Ty0, _Ty1, _Ty...>
			{
				typedef typename _CommonType<
					typename _CommonType<_Ty0, _Ty1>::type, _Ty...
				>::type type;
			};

			template<class...T>
			using _CommonType_t = typename _CommonType<T...>::type;
		}
	}

	namespace __variant
	{
		template<std::size_t size>
		using VariantIndexType =
			std::conditional_t < (size <= std::size_t((std::numeric_limits<signed char>::max)()) + 1), signed char,
			std::conditional_t < (size <= std::size_t((std::numeric_limits<short>::max)()) + 1), short,
			std::conditional_t < (size <= std::size_t((std::numeric_limits<int>::max)()) + 1), int,
			std::conditional_t < (size <= std::size_t((std::numeric_limits<long>::max)()) + 1), long, long long>
			>>>;

		template<class T>
		struct _VariantWrapperTraits
		{
			using type = T;
		};

		template<class T>
		static constexpr T& unwrap(T & v) { return v; }

		//
	#if 0
		template<class T = void> struct _VoidWrapper {};
		template<> struct _VariantWrapperTraits<void> { using type = _VoidWrapper<>; };
		template<> struct _VariantWrapperTraits<const void> { using type = _VoidWrapper<>; };
		template<> struct _VariantWrapperTraits<volatile void> { using type = _VoidWrapper<>; };
		template<> struct _VariantWrapperTraits<const volatile void> { using type = _VoidWrapper<>; };

		template<class T >
		static constexpr _VoidWrapper<T>& unwrap(_VoidWrapper<T> & v) { return v; }

		//#unknown:	value / ref ?
		template <class T>
		class _ReferenceWrapper {
		public:
			typedef T type;
			constexpr _ReferenceWrapper(T& ref) noexcept : _ptr(std::addressof(ref)) {}
			constexpr _ReferenceWrapper(const _ReferenceWrapper&) noexcept = default;

			_ReferenceWrapper(T&&) = delete;

			void operator=(const _ReferenceWrapper& x)noexcept { _ptr = x._ptr; }

			constexpr operator T& () const noexcept { return *_ptr; }

			bool operator==(_ReferenceWrapper const& r) const noexcept { return  *_ptr == *r._ptr; }
			bool operator!=(_ReferenceWrapper const& r) const noexcept { return  *_ptr != *r._ptr; }
			bool operator<(_ReferenceWrapper const& r) const  noexcept { return  *_ptr < *r._ptr; }
			bool operator>(_ReferenceWrapper const& r) const noexcept { return  *_ptr > *r._ptr; }
			bool operator<=(_ReferenceWrapper const& r) const noexcept { return  *_ptr <= *r._ptr; }
			bool operator>=(_ReferenceWrapper const& r) const noexcept { return  *_ptr >= *r._ptr; }
		private:
			T* _ptr;
		};

		template <class T>
		class _RvalueReferenceWrapper {
		public:
			typedef T type;
			constexpr _RvalueReferenceWrapper(T&& rref) noexcept : _ptr(std::addressof(rref)) {}
			constexpr _RvalueReferenceWrapper(const _RvalueReferenceWrapper&) noexcept = default;

			_RvalueReferenceWrapper(T&) = delete;

			void operator=(const _RvalueReferenceWrapper& x)noexcept { _ptr = x._ptr; }

			constexpr operator T& () const noexcept { return *_ptr; }

			bool operator==(_RvalueReferenceWrapper const& r) const noexcept { return std::move(*_ptr) == std::move(*r._ptr); }
			bool operator!=(_RvalueReferenceWrapper const& r) const noexcept { return std::move(*_ptr) != std::move(*r._ptr); }
			bool operator<(_RvalueReferenceWrapper const& r) const noexcept { return std::move(*_ptr) < std::move(*r._ptr); }
			bool operator>(_RvalueReferenceWrapper const& r) const noexcept { return std::move(*_ptr) > std::move(*r._ptr); }
			bool operator<=(_RvalueReferenceWrapper const& r) const noexcept { return std::move(*_ptr) <= std::move(*r._ptr); }
			bool operator>=(_RvalueReferenceWrapper const& r) const noexcept { return std::move(*_ptr) >= std::move(*r._ptr); }
		private:
			T* _ptr;
		};

		template<class T>
		struct _VariantWrapperTraits<T &>
		{
			using type = _ReferenceWrapper<T>;
		};

		template<class T>
		struct _VariantWrapperTraits<T&&>
		{
			using type = _RvalueReferenceWrapper<T>;
		};

		template<class T>
		static constexpr T& unwrap(_ReferenceWrapper<T> & v) { return v; }

	#endif

		template<class T>
		using _UnionValue = typename _VariantWrapperTraits<T>::type;


		template<std::size_t Index>
		struct _VariantUseAllocatorIndex {};

		template<std::size_t Index>
		struct _VariantIndex {};

		template<class IsTriviallyDestructible, class...Types>
		struct _VariantBase;

		template<class IsTriviallyDestructible, class ... Types>
		struct _Union;

		template<class IsTriviallyDestructible >
		struct _Union< IsTriviallyDestructible > {};


		template<class Variant>
		struct _VariantSize
		{
			static_assert(sizeof(Variant) == 0, "error type");
		};

		template<class ... Types>
		struct _VariantSize< variant< Types...> > :std::integral_constant<std::size_t, sizeof...(Types)> {};

		template<class NotCare, class ... Types>
		struct _VariantSize<_VariantBase<NotCare, Types...>> :std::integral_constant<std::size_t, sizeof...(Types)> {};

		template<class NotCare, class ... Types>
		struct _VariantSize<_Union<NotCare, Types...>> :std::integral_constant<std::size_t, sizeof...(Types)> {};

		template< class T, class ... Types>
		struct _Union< std::true_type, T, Types... >
		{
			union
			{
				T									_value;
				_Union<std::true_type, Types...>	_tails;
				_DummyEmpty							__;
			};

			constexpr _Union() :__() {}

			template<class ...Args>
			constexpr _Union(_VariantIndex< 0 >, Args&&... args)
				:_value(std::forward<Args>(args)...)
			{

			}

			template<std::size_t Index, class ...Args>
			constexpr _Union(_VariantIndex<Index>, Args&&... args)
				:_tails(_VariantIndex< Index - 1 >{}, std::forward<Args>(args)...)
			{

			}

			//////////////////////////////////////////////////////////////////////////
			template<std::size_t Index, class... T>
			_Union(_VariantUseAllocatorIndex<Index>, std::tuple<T...> t)
				: _Union(_VariantUseAllocatorIndex<Index>{}, t, std::make_index_sequence< sizeof...(T)  >()) {}

			template<class _Tuple, std::size_t ...Index>
			_Union(_VariantUseAllocatorIndex<0>, _Tuple& t, std::index_sequence<Index...>)
				: _value(std::get<Index>(std::move(t)) ...) {}

			template<std::size_t I, class _Tuple, std::size_t ...Index>
			_Union(_VariantUseAllocatorIndex< I >, _Tuple& t, std::index_sequence<Index...>)
				: _tails(_VariantUseAllocatorIndex< I - 1 >{}, t, std::index_sequence<Index...>{}) {}

			//////////////////////////////////////////////////////////////////////////
			_Union(_Union const& other, _VariantIndex<0>)
				: _value(other._value)
			{

			}

			template<std::size_t Index>
			_Union(_Union const& other, _VariantIndex<Index>)
				: _tails(other, _VariantIndex<Index - 1>())
			{

			}

			_Union(_Union && other, _VariantIndex<0>)
				: _value(std::move(other._value))
			{

			}

			template<std::size_t Index>
			_Union(_Union && other, _VariantIndex<Index>)
				: _tails(std::move(other), _VariantIndex<Index - 1>{})
			{

			}


			template<std::size_t I>
			auto& _Get(std::integral_constant<std::size_t, I >) noexcept
			{
				return _tails._Get(std::integral_constant<std::size_t, I - 1>{});
			}

			auto& _Get(std::integral_constant<std::size_t, 0 >) noexcept
			{
				return _value;
			}

			template<std::size_t I>
			auto& _Get(std::integral_constant<std::size_t, I>) const noexcept
			{
				return _tails._Get(std::integral_constant<std::size_t, I - 1>{});
			}

			auto& _Get(std::integral_constant<std::size_t, 0>) const noexcept
			{
				return _value;
			}

			template<std::size_t I>
			auto& _Get(std::integral_constant<std::size_t, I>) const volatile noexcept
			{
				return _tails._Get(std::integral_constant<std::size_t, I - 1>{});
			}

			auto& _Get(std::integral_constant<std::size_t, 0>) const volatile noexcept
			{
				return _value;
			}

		};

		template< class T, class ... Types>
		struct _Union< std::false_type, T, Types... >
		{
			union
			{
				T									_value;
				_Union<std::false_type, Types...>	_tails;
				_DummyEmpty							__;
			};

			~_Union() {}

			constexpr _Union() :__() {}


			template<class ...Args>
			constexpr _Union(_VariantIndex< 0 >, Args&&... args)
				:_value(std::forward<Args>(args)...)
			{

			}

			template<std::size_t Index, class ...Args>
			constexpr _Union(_VariantIndex< Index >, Args&&... args)
				:_tails(_VariantIndex< Index - 1 >{}, std::forward<Args>(args)...)
			{

			}

			//////////////////////////////////////////////////////////////////////////
			template<std::size_t Index, class... T>
			_Union(_VariantUseAllocatorIndex<Index>, std::tuple<T...> t)
				: _Union(_VariantUseAllocatorIndex<Index>{}, t, std::make_index_sequence< sizeof...(T)  >()) {}

			template<class _Tuple, std::size_t ...Index>
			_Union(_VariantUseAllocatorIndex<0>, _Tuple& t, std::index_sequence<Index...>)
				: _value(std::get<Index>(std::move(t)) ...) {}

			template<std::size_t I, class _Tuple, std::size_t ...Index>
			_Union(_VariantUseAllocatorIndex< I >, _Tuple& t, std::index_sequence<Index...>)
				: _tails(_VariantUseAllocatorIndex< I - 1 >{}, t, std::index_sequence<Index...>{}) {}

			//////////////////////////////////////////////////////////////////////////

			template<std::size_t I>
			auto& _Get(std::integral_constant<std::size_t, I>) noexcept
			{
				return _tails._Get(std::integral_constant<std::size_t, I - 1>{});
			}

			auto& _Get(std::integral_constant<std::size_t, 0 >) noexcept
			{
				return _value;
			}

			template<std::size_t I>
			auto& _Get(std::integral_constant<std::size_t, I>) const noexcept
			{
				return _tails._Get(std::integral_constant<std::size_t, I - 1>{});
			}

			auto& _Get(std::integral_constant<std::size_t, 0 >) const noexcept
			{
				return _value;
			}

			template<std::size_t I>
			auto& _Get(std::integral_constant<std::size_t, I>) const volatile noexcept
			{
				return _tails._Get(std::integral_constant<std::size_t, I - 1>{});
			}

			auto& _Get(std::integral_constant<std::size_t, 0 >) const volatile noexcept
			{
				return _value;
			}

		};

		//////////////////////////////////////////////////////////////////////////

		template<class R, std::size_t Index, std::size_t Size, class Visitor, class... Args,
			class = void, class = std::enable_if_t< (Index < Size) > >
			constexpr inline
			R _InvokeIndexFn(Visitor&& v, Args&& ...args)
		{
			return std::forward<Visitor>(v).template invoke<Index>(std::forward<Args>(args)...);
		}

		template<class R, std::size_t Index, std::size_t Size, class Visitor, class... Args,
			class = std::enable_if_t< (Index >= Size) > >
			constexpr inline
			R _InvokeIndexFn(Visitor&& v, Args&& ...args)
		{
			assert(false);
			return std::forward<Visitor>(v).template invoke<0>(std::forward<Args>(args)...);
		}


		template<class R, class Visitor, class... Args, std::size_t ...Index>
		constexpr inline decltype(auto) _InvokeIndexImplFuncPtr(Visitor&& v, std::size_t index, std::index_sequence<Index...>, Args&& ...args)
		{

			using Fn = R(*)(Visitor&&, Args&&...);
			Fn fns[] = { _InvokeIndexFn<R,Index, sizeof...(Index),Visitor, Args ... > ..., nullptr };
			return fns[index](std::forward<Visitor>(v), std::forward<Args>(args)...);
		}

		//
		template<class R,
			std::size_t I,
			std::size_t Size,
			class Visitor,
			class... Args,
			class = void,
			class = std::enable_if_t<(I + 1 < Size)>>
			constexpr inline decltype(auto) _InvokeIndexImplOneByOneHelper(Visitor&& v,
																		   std::size_t index,
																		   Args&& ...args)
		{
			if(I == index)
			{
				return _InvokeIndexFn<R, I, Size >(std::forward<Visitor>(v), std::forward<Args>(args)...);
			}
			else
			{
				return _InvokeIndexImplOneByOneHelper<R, I + 1, Size>(std::forward<Visitor>(v), index, std::forward<Args>(args)...);
			}
		}


		template<class R,
			std::size_t I,
			std::size_t Size,
			class Visitor,
			class... Args,
			class = std::enable_if_t<I + 1 == Size >>
			constexpr inline decltype(auto) _InvokeIndexImplOneByOneHelper(Visitor&& v,
																		   std::size_t index,
																		   Args&& ...args)
		{
			assert(index == I);
			return _InvokeIndexFn<R, I, Size >(std::forward<Visitor>(v), std::forward<Args>(args)...);
		}



		template<class R, std::size_t Size, class Visitor, class... Args>
		constexpr inline R _InvokeIndexImplOneByOne(Visitor&& v,
													std::size_t index,
													Args&& ...args)
		{
			return _InvokeIndexImplOneByOneHelper<R, 0, Size>(std::forward<Visitor>(v),
															  index,
															  std::forward<Args>(args)...);
		}

		//////////////////////////////////////////////////////////////////////////
		template<class Visitor,
			class... Args,
			std::size_t ...Index,
			//#X return common type
			class R = _CommonType_t < decltype(std::declval<Visitor>().template invoke<Index>(std::declval<Args>()...))... >>
			constexpr inline R _VisitVariantImpl2(Visitor&& v,
												  std::size_t index,
												  std::index_sequence<Index...>,
												  Args&& ...args)
		{
			assert(index < sizeof...(Index));
			return _InvokeIndexImplOneByOne<R, sizeof...(Index) >(std::forward<Visitor>(v),
																  index,
																  std::forward<Args>(args)...);
		}

		//////////////////////////////////////////////////////////////////////////

		template<class Visitor, class VariantLike, class...Args, std::size_t Size = _VariantSize<std::decay_t<VariantLike>>::value >
		constexpr inline decltype(auto) _VisitVariantImpl(Visitor&& v, VariantLike && u, std::size_t index, Args&& ...args)
		{
			return _VisitVariantImpl2(std::forward<Visitor>(v),
									  index,
									  std::make_index_sequence< Size>(),
									  std::forward<VariantLike>(u),
									  std::forward<Args>(args)...);
		}


		//////////////////////////////////////////////////////////////////////////
		struct _CopyVisitor
		{
			template<std::size_t I, class V, class U>
			void invoke(V&& v, U&& u)
			{
				new (static_cast<void*>(&u._Get(std::integral_constant<std::size_t, I>{})))
					auto(v._Get(std::integral_constant<std::size_t, I>{}));
			}

			template<std::size_t I, class V, class U, class Alloc>
			void invoke(V&& v, U&& u, Alloc&& a)
			{
				new (static_cast<void*>(&u))
					std::decay_t<U>(_VariantUseAllocatorIndex<I>{},
									_ForwardAllocConstructorArgs(a, v._Get(std::integral_constant<std::size_t, I>{})));
			}
		};

		struct _MoveVisitor
		{
			template<std::size_t I, class V, class U>
			void invoke(V&& v, U&& u)
			{
				new (static_cast<void*>(&u._Get(std::integral_constant<std::size_t, I>{})))
					auto(std::move(v._Get(std::integral_constant<std::size_t, I>{})));
			}

			template<std::size_t I, class V, class U, class Alloc>
			void invoke(V&& v, U&& u, Alloc&& a)
			{
				new (static_cast<void*>(&u))
					std::decay_t<U>(_VariantUseAllocatorIndex<I>{},
									_ForwardAllocConstructorArgs(a, std::move(v._Get(std::integral_constant<std::size_t, I>{}))));
			}
		};

		struct _CopyAssignVisitor
		{
			template<std::size_t I, class V, class U>
			void invoke(V&& v, U&& u)
			{
				u._Get(std::integral_constant<std::size_t, I>{}) = v._Get(std::integral_constant<std::size_t, I>{});
			}
		};

		struct _MoveAssignVisitor
		{
			template<std::size_t I, class V, class U>
			void invoke(V&& v, U&& u)
			{
				u._Get(std::integral_constant<std::size_t, I>{}) = std::move(v._Get(std::integral_constant<std::size_t, I>{}));
			}
		};

		struct _SwapVisitor
		{
			template<std::size_t I, class V, class U>
			void invoke(V&& v, U&& u)
			{
				//
				using std::swap;
				swap(u._Get(std::integral_constant<std::size_t, I>{}), v._Get(std::integral_constant<std::size_t, I>{}));
			}
		};

		struct _DestoryVisitor
		{
			template<class T>
			static inline void _Destory(T*p) { p->~T(); }
			template<std::size_t I, class V>
			void invoke(V&& v)
			{
				_Destory(&v._Get(std::integral_constant<std::size_t, I>{}));
			}
		};
	}

	namespace __variant {

		template<class...Types>
		struct _VariantBase <std::true_type, Types...>
		{
			using union_t = _Union<std::true_type, _UnionValue< Types> ...>;
			using index_t = VariantIndexType<sizeof...(Types)>;
			static const auto npos = index_t(-1);

			union_t											_union;
			index_t											_index;

			constexpr _VariantBase() :_union(_VariantIndex<0>{}), _index(0) {}


			template <class T, class = std::enable_if_t< !std::is_same< std::decay_t<T>, _VariantBase  >::value	> >
			constexpr _VariantBase(T&& t) noexcept(std::is_nothrow_constructible< pack_element_t<_OverloadIndexOf<T&&, Types...>::value, Types...>, T&&>::value)
				: _union(_VariantIndex< _OverloadIndexOf<T&&, Types...>::value>{}, std::forward<T>(t))
				, _index{ _OverloadIndexOf<T&&, Types...>::value }
			{

			}

			template <std::size_t I, class... Args>
			constexpr explicit _VariantBase(in_place_index_t<I>, Args&&... args)
				: _union(_VariantIndex< I >{}, std::forward<Args>(args)...)
				, _index{ I }
			{

			}

			template <std::size_t I, class U, class... Args>
			constexpr explicit _VariantBase(in_place_index_t<I>, std::initializer_list<U> il, Args&&... args)
				: _union(_VariantIndex< I >{}, il, std::forward<Args>(args)...)
				, _index{ I }
			{

			}

			_VariantBase(const _VariantBase& other)
				:_index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_CopyVisitor{}, other._union, other._index, this->_union);
				}
			}
			_VariantBase(_VariantBase&& other)
				:_index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_MoveVisitor{}, other._union, other._index, this->_union);
				}
			}


			//////////////////////////////////////////////////////////////////////////
			template <class Alloc>
			_VariantBase(std::allocator_arg_t, const Alloc& a)
				:_union(_VariantUseAllocatorIndex<0>{}, _ForwardAllocConstructorArgs<pack_element_t< 0, Types... >>(a))
				, _index(0)
			{

			}

			template <class Alloc, class T, class = std::enable_if_t< !std::is_same< std::decay_t<T>, _VariantBase  >::value	>>
			_VariantBase(std::allocator_arg_t, const Alloc& a, T&& t)
				:_union(_VariantUseAllocatorIndex<_OverloadIndexOf<T&&, Types...>::value >{}, _ForwardAllocConstructorArgs<pack_element_t< _OverloadIndexOf<T&&, Types...>::value, Types... >>(a, std::forward<T>(t)))
				, _index{ _OverloadIndexOf<T&&, Types...>::value }
			{

			}


			template <class Alloc, size_t I, class... Args>
			_VariantBase(std::allocator_arg_t, const Alloc& a, in_place_index_t<I>, Args&&...args)
				:_union(_VariantUseAllocatorIndex<I>{}, _ForwardAllocConstructorArgs<pack_element_t<I, Types... >>(a, std::forward<Args>(args)...))
				, _index{ I }
			{

			}

			template <class Alloc, size_t I, class U, class... Args>
			_VariantBase(std::allocator_arg_t, const Alloc& a, in_place_index_t<I>, std::initializer_list<U> il, Args&&...args)
				:_union(_VariantUseAllocatorIndex<I>{}, _ForwardAllocConstructorArgs<pack_element_t<I, Types... >>(a, il, std::forward<Args>(args)...))
				, _index{ I }
			{

			}

			template <class Alloc>
			_VariantBase(std::allocator_arg_t, const Alloc& a, const _VariantBase& other)
				: _index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_CopyVisitor{}, other._union, other._index, _union, a);
				}
			}

			template <class Alloc>
			_VariantBase(std::allocator_arg_t, const Alloc& a, _VariantBase&& other)
				:_union(other._index, a, std::move(other._union))
				, _index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_MoveVisitor{}, other._union, other._index, _union, a);
				}
			}


			//////////////////////////////////////////////////////////////////////////
			void operator=(const _VariantBase& rhs)
			{
				if(_HasValue())
				{
					if(rhs._HasValue())
					{
						if(_index == rhs._index)
						{
							_VisitVariantImpl(_CopyAssignVisitor{}, rhs._union, _index, this->_union);
						}
						else
						{
							union_t tmpUnion;
							_VisitVariantImpl(_CopyVisitor{}, rhs._union, rhs._index, tmpUnion);
							_Reset();
							_VisitVariantImpl(_MoveVisitor{}, tmpUnion, rhs._index, this->_union);
							_index = rhs._index;
						}
					}
					else
					{
						_Reset();
					}
				}
				else
				{
					if(rhs._HasValue())
					{
						union_t tmpUnion;
						_VisitVariantImpl(_CopyVisitor{}, rhs._union, rhs._index, tmpUnion);
						_VisitVariantImpl(_MoveVisitor{}, tmpUnion, rhs._index, this->_union);
						_index = rhs._index;
					}
				}
			}

			void operator=(_VariantBase&& rhs)
			{
				if(_HasValue())
				{
					if(rhs._HasValue())
					{
						if(_index == rhs._index)
						{
							_VisitVariantImpl(_MoveAssignVisitor{}, rhs._union, _index, this->_union);

						}
						else
						{
							_Reset();
							_VisitVariantImpl(_MoveVisitor{}, rhs._union, rhs._index, this->_union);
							_index = rhs._index;
						}
					}
					else
					{
						_Reset();
					}
				}
				else
				{
					if(rhs._HasValue())
					{
						_VisitVariantImpl(_MoveVisitor{}, rhs._union, rhs._index, this->_union);
						_index = rhs._index;
					}
				}
			}


			template <class T, std::size_t index = _OverloadIndexOf<T, Types...>::value,
				class = std::enable_if_t<
				!std::is_same< std::decay_t<T>, _VariantBase  >::value	>>
				void operator=(T&& t) noexcept(std::is_nothrow_assignable< pack_element_t<index, Types...>&, T&&>::value && std::is_nothrow_constructible<pack_element_t<index, Types...>, T&&>::value)
			{
				if(_index == index)
				{
					_union._Get(std::integral_constant<std::size_t, index>{}) = std::forward<T>(t);
				}
				else
				{
					_Reset();
					new (static_cast<void*>(&_union)) union_t(_VariantIndex<index>{}, std::forward<T>(t));
					_index = { index };
				}
			}




			//
			template <size_t I, class... Args>
			void emplace(Args&&... args)
			{
				_Reset();
				new (static_cast<void*>(&_union)) union_t(_VariantIndex<I>{}, std::forward<Args>(args)...);
				_index = { I };
			}

			template <size_t I, class U, class... Args>
			void emplace(std::initializer_list<U> il, Args&&... args)
			{
				_Reset();
				new (static_cast<void*>(&_union)) union_t(_VariantIndex<I>{}, il, std::forward<Args>(args)...);
				_index = { I };
			}


			void swap(_VariantBase& rhs)
			{
				if(!_HasValue() && !rhs._HasValue())
				{
					return;
				}
				if(_index == rhs._index)
				{
					_VisitVariantImpl(_SwapVisitor{}, _union, _index, rhs._union);
				}
				else
				{
					_VariantBase tmp(std::move(rhs));
					rhs.operator=(std::move(*this));
					operator=(std::move(tmp));
				}
			}



			///
			template<std::size_t I>
			auto& _Get() noexcept
			{
				return _union._Get(std::integral_constant<std::size_t, I>{});
			}
			template<std::size_t I>
			auto& _Get() const noexcept
			{
				return _union._Get(std::integral_constant<std::size_t, I>{});
			}

			template<std::size_t I>
			auto& _Get() const volatile noexcept
			{
				return _union._Get(std::integral_constant<std::size_t, I>{});
			}


			void _Reset() { _index = { npos }; }

			constexpr bool			_HasValue() const noexcept { return _index != npos; }
			constexpr std::size_t	_Index() const noexcept { return _index; }
			constexpr auto			_rawIndex() const noexcept { return _index; }
		};


		//////////////////////////////////////////////////////////////////////////
		template<class...Types>
		struct _VariantBase<std::false_type, Types...>
		{
			using union_t = _Union<std::false_type, _UnionValue< Types> ...>;
			using index_t = VariantIndexType<sizeof...(Types)>;
			static const auto npos = index_t(-1);

			union_t											_union;
			index_t											_index;

			constexpr _VariantBase() :_union(_VariantIndex<0>{}), _index(0) {}


			template <class T, class = std::enable_if_t< !std::is_same< std::decay_t<T>, _VariantBase  >::value	> >
			constexpr _VariantBase(T&& t) noexcept(std::is_nothrow_constructible< pack_element_t<_OverloadIndexOf<T&&, Types...>::value, Types...>, T&&>::value)
				: _union(_VariantIndex< _OverloadIndexOf<T&&, Types...>::value>{}, std::forward<T>(t))
				, _index{ _OverloadIndexOf<T&&, Types...>::value }
			{

			}

			template <std::size_t I, class... Args>
			constexpr explicit _VariantBase(in_place_index_t<I>, Args&&... args)
				: _union(_VariantIndex< I >{}, std::forward<Args>(args)...)
				, _index{ I }
			{

			}

			template <std::size_t I, class U, class... Args>
			constexpr explicit _VariantBase(in_place_index_t<I>, std::initializer_list<U> il, Args&&... args)
				: _union(_VariantIndex< I >{}, il, std::forward<Args>(args)...)
				, _index{ I }
			{

			}

			_VariantBase(const _VariantBase& other)
				:_index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_CopyVisitor{}, other._union, other._index, this->_union);
				}
			}
			_VariantBase(_VariantBase&& other)
				:_index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_MoveVisitor{}, other._union, other._index, this->_union);
				}
			}

			//////////////////////////////////////////////////////////////////////////
			template <class Alloc>
			_VariantBase(std::allocator_arg_t, const Alloc& a)
				:_union(_VariantUseAllocatorIndex<0>{}, _ForwardAllocConstructorArgs<pack_element_t< 0, Types... >>(a))
				, _index(0)
			{

			}

			template <class Alloc, class T, class = std::enable_if_t< !std::is_same< std::decay_t<T>, _VariantBase  >::value	>>
			_VariantBase(std::allocator_arg_t, const Alloc& a, T&& t)
				:_union(_VariantUseAllocatorIndex<_OverloadIndexOf<T&&, Types...>::value >{}, _ForwardAllocConstructorArgs<pack_element_t< _OverloadIndexOf<T&&, Types...>::value, Types... >>(a, std::forward<T>(t)))
				, _index{ _OverloadIndexOf<T&&, Types...>::value }
			{

			}


			template <class Alloc, size_t I, class... Args>
			_VariantBase(std::allocator_arg_t, const Alloc& a, in_place_index_t<I>, Args&&...args)
				:_union(_VariantUseAllocatorIndex<I>{}, _ForwardAllocConstructorArgs<pack_element_t<I, Types... >>(a, std::forward<Args>(args)...))
				, _index{ I }
			{

			}

			template <class Alloc, size_t I, class U, class... Args>
			_VariantBase(std::allocator_arg_t, const Alloc& a, in_place_index_t<I>, std::initializer_list<U> il, Args&&...args)
				:_union(_VariantUseAllocatorIndex<I>{}, _ForwardAllocConstructorArgs<pack_element_t<I, Types... >>(a, il, std::forward<Args>(args)...))
				, _index{ I }
			{

			}

			template <class Alloc>
			_VariantBase(std::allocator_arg_t, const Alloc& a, const _VariantBase& other)
				: _index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_CopyVisitor{}, other._union, other._index, _union, a);
				}
			}

			template <class Alloc>
			_VariantBase(std::allocator_arg_t, const Alloc& a, _VariantBase&& other)
				:_union(other._index, a, std::move(other._union))
				, _index(other._index)
			{
				if(other._HasValue())
				{
					_VisitVariantImpl(_MoveVisitor{}, other._union, other._index, _union, a);
				}
			}


			//////////////////////////////////////////////////////////////////////////


			~_VariantBase()
			{
				_Reset();
			}
			void operator=(const _VariantBase& rhs)
			{
				if(_HasValue())
				{
					if(rhs._HasValue())
					{
						if(_index == rhs._index)
						{
							_VisitVariantImpl(_CopyAssignVisitor{}, rhs._union, _index, this->_union);
						}
						else
						{
							union_t tmpUnion;
							_VisitVariantImpl(_CopyVisitor{}, rhs._union, rhs._index, tmpUnion);
							_Reset();
							_VisitVariantImpl(_MoveVisitor{}, tmpUnion, rhs._index, this->_union);
							_index = rhs._index;
						}
					}
					else
					{
						_Reset();
					}
				}
				else
				{
					if(rhs._HasValue())
					{
						union_t tmpUnion;
						_VisitVariantImpl(_CopyVisitor{}, rhs._union, rhs._index, tmpUnion);
						_VisitVariantImpl(_MoveVisitor{}, tmpUnion, rhs._index, this->_union);
						_index = rhs._index;
					}
				}
			}

			void operator=(_VariantBase&& rhs)
			{
				if(_HasValue())
				{
					if(rhs._HasValue())
					{
						if(_index == rhs._index)
						{
							_VisitVariantImpl(_MoveAssignVisitor{}, rhs._union, _index, this->_union);

						}
						else
						{
							_Reset();
							_VisitVariantImpl(_MoveVisitor{}, rhs._union, rhs._index, this->_union);
							_index = rhs._index;
						}
					}
					else
					{
						_Reset();
					}
				}
				else
				{
					if(rhs._HasValue())
					{
						_VisitVariantImpl(_MoveVisitor{}, rhs._union, rhs._index, this->_union);
						_index = rhs._index;
					}
				}
			}


			template <class T, std::size_t index = _OverloadIndexOf<T, Types...>::value,
				class = std::enable_if_t<
				!std::is_same< std::decay_t<T>, _VariantBase  >::value	>>
				void operator=(T&& t) noexcept(std::is_nothrow_assignable< pack_element_t<index, Types...>&, T&&>::value && std::is_nothrow_constructible<pack_element_t<index, Types...>, T&&>::value)
			{
				if(_index == index)
				{
					_union._Get(std::integral_constant<std::size_t, index>{}) = std::forward<T>(t);
				}
				else
				{
					_Reset();
					new (static_cast<void*>(&_union)) union_t(_VariantIndex<index>{}, std::forward<T>(t));
					_index = { index };
				}
			}

			//
			template <size_t I, class... Args>
			void emplace(Args&&... args)
			{
				_Reset();
				new (static_cast<void*>(&_union)) union_t(_VariantIndex<I>{}, std::forward<Args>(args)...);
				_index = { I };
			}

			template <size_t I, class U, class... Args>
			void emplace(std::initializer_list<U> il, Args&&... args)
			{
				_Reset();
				new (static_cast<void*>(&_union)) union_t(_VariantIndex<I>{}, il, std::forward<Args>(args)...);
				_index = { I };
			}


			void swap(_VariantBase& rhs)
			{
				if(!_HasValue() && !rhs._HasValue())
				{
					return;
				}
				if(_index == rhs._index)
				{
					_VisitVariantImpl(_SwapVisitor{}, _union, _index, rhs._union);
				}
				else
				{
					_VariantBase tmp(std::move(rhs));
					rhs.operator=(std::move(*this));
					operator=(std::move(tmp));
				}
			}

			template<std::size_t I>
			auto& _Get() noexcept
			{
				return _union._Get(std::integral_constant<std::size_t, I>{});
			}
			template<std::size_t I>
			auto& _Get() const noexcept
			{
				return _union._Get(std::integral_constant<std::size_t, I>{});
			}

			template<std::size_t I>
			auto& _Get() const volatile noexcept
			{
				return _union._Get(std::integral_constant<std::size_t, I>{});
			}


			void _Reset()
			{
				if(_HasValue())
				{
					_VisitVariantImpl(_DestoryVisitor{}, _union, _index);
					_index = { npos };
				}
			}

			constexpr bool			_HasValue() const noexcept { return _index != npos; }
			constexpr std::size_t	_Index() const noexcept { return _index; }
			constexpr auto			_rawIndex() const noexcept { return _index; }
		};

		template<class Cmp>
		struct _CompareVisitor
		{
			template<std::size_t I, class V>
			bool invoke(V&& v, V&& w) const
			{
				return Cmp{}(v._Get(std::integral_constant<std::size_t, I>{}), w._Get(std::integral_constant<std::size_t, I>{}));
			}
		};

		template<class V>
		bool Less(V const& l, V const& r)
		{
			return _VisitVariantImpl(_CompareVisitor<std::less<void>>{}, l._union, l._index, r._union);
		}

		template<class V>
		bool _Equal(V const& l, V const& r)
		{
			return _VisitVariantImpl(_CompareVisitor<std::equal_to<void>>{}, l._union, l._index, r._union);
		}

		template<class V>
		bool _UnEqual(V const& l, V const& r)
		{
			return _VisitVariantImpl(_CompareVisitor<std::not_equal_to<void>>{}, l._union, l._index, r._union);
		}

		template<class V>
		bool _Greater(V const& l, V const& r)
		{
			return _VisitVariantImpl(_CompareVisitor<std::greater<void>>{}, l._union, l._index, r._union);
		}

		template<class V>
		bool _LessEqual(V const& l, V const& r)
		{
			return _VisitVariantImpl(_CompareVisitor<std::less_equal<void>>{}, l._union, l._index, r._union);
		}

		template<class V>
		bool _GreaterEqual(V const& l, V const& r)
		{
			return _VisitVariantImpl(_CompareVisitor<std::greater_equal<void>>{}, l._union, l._index, r._union);
		}
	}
}

#include "../config/config_end.h"
